package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.client.TrackInfoFeignClient;
import com.atguigu.tingshu.album.mapper.*;
import com.atguigu.tingshu.album.service.AlbumAttributeValueService;
import com.atguigu.tingshu.album.service.AlbumInfoService;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.album.*;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.order.client.OrderInfoFeignClient;
import com.atguigu.tingshu.query.album.AlbumInfoQuery;
import com.atguigu.tingshu.vo.album.AlbumAttributeValueVo;
import com.atguigu.tingshu.vo.album.AlbumInfoVo;
import com.atguigu.tingshu.vo.album.AlbumListVo;
import com.atguigu.tingshu.vo.album.AlbumStatVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import kotlin.jvm.internal.Lambda;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class AlbumInfoServiceImpl extends ServiceImpl<AlbumInfoMapper, AlbumInfo> implements AlbumInfoService {

	@Autowired
	private AlbumInfoMapper albumInfoMapper;

    @Autowired
    private AlbumAttributeValueMapper albumAttributeValueMapper;
    
    @Autowired
    private AlbumStatMapper albumStatMapper;

    @Autowired
    private AlbumAttributeValueService albumAttrAndValueService;

    @Autowired
    private TrackInfoMapper trackInfoMapper;

    @Autowired
    private RabbitService rabbitService;

    @Autowired
    private BaseCategory2Mapper category2Mapper;

    @Autowired
    private BaseCategory3Mapper category3Mapper;


    @Autowired
    private OrderInfoFeignClient orderInfoFeignClient;

    @Autowired
    private TrackInfoFeignClient trackInfoFeignClient;


    /**
     * 保存专辑信息
     * @param albumInfoVo 专辑信息vo
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveAlbumInfo(AlbumInfoVo albumInfoVo) {

        AlbumInfoServiceImpl proxy = (AlbumInfoServiceImpl) AopContext.currentProxy();

        /**
         * 保存专辑信息我们需要对三张表进行操作
         * 1.album_info             --> 专辑信息表
         * 2.album_attribute_value  --> 专辑属性值中间表
         * 3.album_stat             --> 专辑数据统计表
         */

        //1.对album_info表进行操作
        //将vo对象的值存入实体类对象
        AlbumInfo albumInfo = new AlbumInfo();
        BeanUtils.copyProperties(albumInfoVo, albumInfo);
        //为实体类对象的userId属性赋值
        Long userId = AuthContextHolder.getUserId();
        albumInfo.setUserId(userId);
        //为实体类的状态status属性赋值，设置为通过
        albumInfo.setStatus(SystemConstant.ALBUM_STATUS_PASS);
        //对实体类进行判断，若支付类型不为免费类型，那么我们就设置前5集免费收听
        if (!SystemConstant.ALBUM_PAY_TYPE_FREE.equals(albumInfo.getPayType())){
            albumInfo.setTracksForFree(5);
        }
        //将实体类存入数据库中 --> 保存专辑
        albumInfoMapper.insert(albumInfo);
        log.info("[保存专辑信息] -> album_info -> 成功");

        //2.对album_attribute_value表进行操作
        //从vo对象中取出albumAttributeValueVoList集合
        List<AlbumAttributeValueVo> albumAttributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
        //遍历集合,将集合中的数据存入数据库当中
        if (!CollectionUtils.isEmpty(albumAttributeValueVoList)){
            for (AlbumAttributeValueVo albumAttributeValueVo : albumAttributeValueVoList) {
                AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
                albumAttributeValue.setAlbumId(albumInfo.getId());
                albumAttributeValue.setAttributeId(albumAttributeValueVo.getAttributeId());
                albumAttributeValue.setValueId(albumAttributeValueVo.getValueId());
                albumAttributeValueMapper.insert(albumAttributeValue);
            }
        }
        log.info("[保存专辑信息] -> album_attribute_value -> 成功");
        
        //3.对album_stat表进行操作
        proxy.initAlbumStat(albumInfo.getId());
        log.info("[保存专辑信息] -> album_stat -> 成功");

        //4.发送消息给mq队列，让search微服务的消费者去消费消息，即上传专辑信息到es中
        rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM,MqConst.ROUTING_ALBUM_UPPER,albumInfo.getId().toString());

    }

    /**
     * 分页查询用户专辑信息
     * @param query 查询参数
     * @return 分页专辑信息
     */
    @Override
    public IPage<AlbumListVo> findUserAlbumPage(IPage<AlbumListVo> albumListVoPage, AlbumInfoQuery query) {
        return albumInfoMapper.findUserAlbumPage(albumListVoPage,query);
    }

    /**
     * 根据专辑id查询专辑信息
     * @param albumId 专辑id
     * @return
     */
    @Override
    public AlbumInfo getAlbumInfo(Long albumId) {
        AlbumInfo albumInfo = getById(albumId);
        List<AlbumAttributeValue> albumAttributeValueList = albumAttributeValueMapper.selectList(
                new LambdaQueryWrapper<AlbumAttributeValue>()
                .eq(AlbumAttributeValue::getAlbumId, albumId));
        albumInfo.setAlbumAttributeValueVoList(albumAttributeValueList);
        return albumInfo;
    }


    /**
     * 修改专辑信息
     * @param albumInfoVo 修改对象vo
     * @param userId 用户id
     * @param albumId 专辑id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateAlbumInfo(AlbumInfoVo albumInfoVo, Long userId, Long albumId) {
        /**
         * 具体思路：
         * 我们如果要修改专辑，我们需要对如下表进行操作：
         * 1.album_info             --> 将最新的专辑信息存入数据库中
         * 2.album_attribute_value  --> 删除原先中间表中专辑信息和属性值信息的对应关系，再重新存入一份最新的
         */

        //1.我们先来修改album_info表，我们只能使用实体类和数据库进行交互
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        if (null == albumInfo){
            throw new GuiguException(201,"目标专辑对象不存在");
        }
        //1.1.获取到了albumInfo的实体类对象，我们将vo中和实体类统一的属性进行值的覆盖
        BeanUtils.copyProperties(albumInfoVo,albumInfo);
        //1.2.我们需要对特殊情况进行处理，如果修改后的专辑的支付类型为免费类型，那么我们需要将前5集免费收听设置为0
        //  以及价格置为0，折扣等等修改为-1
        //  如果修改后的专辑的支付类型为付费类型，那么我们需要设置前五集免费收听

        //1.3 如果修改后的专辑支付类型为免费类型
        if (SystemConstant.ALBUM_PAY_TYPE_FREE.equals(albumInfo.getPayType())){
            //对价格进行修改
            albumInfo.setPrice(new BigDecimal(0));
            //对折扣信息进行修改
            albumInfo.setDiscount(new BigDecimal(-1));
            albumInfo.setVipDiscount(new BigDecimal(-1));
            //将免费收听数量进行修改
            albumInfo.setTracksForFree(0);
        } else {
            //1.4 如果支付类型为付费类型，那么我们需要将免费收听数量设置为5
            albumInfo.setTracksForFree(5);
        }
        //1.5 将封装好的实体类对象存入数据库
        albumInfoMapper.updateById(albumInfo);

        //2.对album_attribute_value表进行操作
        //2.1 从album_attribute_value找出旧的中间关系数据，将其删除
        albumAttributeValueMapper.delete(new LambdaQueryWrapper<AlbumAttributeValue>()
                .eq(AlbumAttributeValue::getAlbumId,albumId));
        //2.2 封装新的数据
        List<AlbumAttributeValueVo> attributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();

        List<AlbumAttributeValue> list = attributeValueVoList.stream().map(vo -> {
            AlbumAttributeValue entity = new AlbumAttributeValue();
            entity.setAttributeId(vo.getAttributeId());
            entity.setValueId(vo.getValueId());
            entity.setAlbumId(albumId);
            return entity;
        }).toList();

        if (!CollectionUtils.isEmpty(list)){
            //2.3 将实体类集合集体存入数据库中
            albumAttrAndValueService.saveBatch(list);
        }

        //如果状态为开放状态，那么就上传到es当中
        if (albumInfoVo.getIsOpen().equals("1")){
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM,MqConst.ROUTING_ALBUM_UPPER,albumId.toString());
            log.info("专辑微服务发送消息到搜索微服务指定的队列，完成专辑：{}上架成功：", albumId);
        } else {
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_LOWER, albumId.toString());
            log.info("专辑微服务发送消息到搜索微服务指定的队列，完成专辑：{}下架成功：", albumId);
        }

    }

    /**
     * 根据指定的专辑id删除专辑信息
     * @param albumId 专辑id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeAlbumInfo(Long albumId) {

        /**
         * 我们如果要删除一张专辑信息
         * 我们需要对如下表进行操作:
         * 1.album_info
         * 2.album_attribute_value
         * 3.album_stat
         */

        //我们如果要删除一个专辑，我们要优先判断该专辑底下有没有声音，若有，则提醒不许删除
        //1.我们先根据专辑id去track_info表中获取声音信息的数量
        Long count = trackInfoMapper.selectCount(new LambdaQueryWrapper<TrackInfo>()
                .eq(TrackInfo::getAlbumId, albumId));
        if (count > 0){
            throw new GuiguException(201,"专辑下有音轨存在，不建议删除");
        }
        //1.1 根据指定的专辑id，删除album_info表中的信息
        albumInfoMapper.deleteById(albumId);

        //2.删除album_attribute_value表下的信息
        albumAttributeValueMapper.delete(new LambdaQueryWrapper<AlbumAttributeValue>()
                .eq(AlbumAttributeValue::getAlbumId,albumId));

        //3.删除album_stat表中的信息
        albumStatMapper.delete(new LambdaQueryWrapper<AlbumStat>()
                .eq(AlbumStat::getAlbumId,albumId));

        rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_LOWER, albumId.toString());
        log.info("专辑微服务发送消息到搜索微服务指定的队列，完成专辑：{}下架成功：", albumId);
    }

    /**
     * 查询当前用户名下的所有专辑信息
     * @param userId 用户id
     * @return
     */
    @Override
    public List<AlbumInfo> findUserAllAlbumList(Long userId) {
        LambdaQueryWrapper<AlbumInfo> queryWrapper = new LambdaQueryWrapper<AlbumInfo>().eq(AlbumInfo::getUserId, userId)
                .eq(AlbumInfo::getIsDeleted, 0);
        List<AlbumInfo> list = albumInfoMapper.selectList(queryWrapper);
        return list;
    }

    /**
     * [rpc] 根据专辑id获取专辑详情信息【四个维度】
     * @param albumId 专辑id
     * @return 专辑信息
     */
    @Override
    public AlbumStatVo getAlbumStatVoByAlbumId(Long albumId) {
        return albumInfoMapper.getAlbumStatVoByAlbumId(albumId);
    }


    /**
     * [rpc]
     * 根据一级分类id获取对应的前7个三级分类id对象
     * @param category1Id c1Id
     * @return 前七个三级分类id对象
     */
    @Override
    public List<BaseCategory3> getTop7Category3ByCategory1Id(Long category1Id) {
        //1.根据一级分类id获取二级分类id对象集合
        List<BaseCategory2> category2List = category2Mapper.selectList(new LambdaQueryWrapper<BaseCategory2>()
                .eq(BaseCategory2::getCategory1Id, category1Id)
                .eq(BaseCategory2::getIsDeleted,0));
        if (CollectionUtils.isEmpty(category2List)){
            throw new GuiguException(201,"当前一级分类id下不存在二级分类");
        }
        //2.根据二级分类id对象集合获取 二级分类ID集合
        List<Long> c2IdList = category2List.stream().map(BaseCategory2::getId).toList();

        //3.根据二级分类id集合，获取三级分类对象
        List<BaseCategory3> category3List = category3Mapper.selectList(new LambdaQueryWrapper<BaseCategory3>()
                .in(BaseCategory3::getCategory2Id, c2IdList)
                .eq(BaseCategory3::getIsDeleted, 0)
                .eq(BaseCategory3::getIsTop, 1)
                .last("limit 7"));
        if (CollectionUtils.isEmpty(category3List)){
           return new ArrayList<>();
        }
        return category3List;
    }


    /**
     * [rpc]
     * 获取所有专辑id集合
     * @return 专辑id集合
     */
    @Override
    public List<Long> getAllAlbumIdList() {
        LambdaQueryWrapper<AlbumInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(AlbumInfo::getId);
        List<AlbumInfo> albumInfoList = albumInfoMapper.selectList(wrapper);
        return albumInfoList.stream().map(AlbumInfo::getId).toList();
    }


    /**
     * [rpc]
     * 根据音频id获取音频对象
     * @param trackId 音频id
     * @return 音频对象
     */
    @Override
    public TrackInfo getTrackInfoById(Long trackId) {

        return trackInfoMapper.selectById(trackId);
    }


    /**
     * 根据订单号,修改mysql中的专辑的购买量
     * @param orderNo 订单号
     */
    @Override
    public void listenAlbumStatUpdate(String orderNo) {
        //1.根据订单号获取订单对象
        Result<OrderInfo> orderInfoResult = orderInfoFeignClient.getOrderInfoByOrderNo(orderNo);
        OrderInfo orderInfo = orderInfoResult.getData();
        Assert.notNull(orderInfo,"[AlbumInfoServiceImpl] 调用order微服务的 [getOrderInfoByOrderNo]方法失败");

        //2.获取参数
        //订单购买量
        int orderSize = orderInfo.getOrderDetailList().size();
        //订单类型
        String itemType = orderInfo.getItemType();

        //3.根据订单类型,获取真正的专辑id
        Long albumId = null;
        if ("1001".equals(itemType)){
            //专辑,那么我们去修改专辑的购买量,传来的订单详情中就包含了专辑id
            albumId = orderInfo.getOrderDetailList().get(0).getItemId();
        } else if ("1002".equals(itemType)){
            //音频,那么我们需要去修改专辑的购买量,传来的订单中只有音频id,需要根据音频id获取音频对象在获取专辑id
            Long trackId = orderInfo.getOrderDetailList().get(0).getItemId();
            Result<TrackInfo> trackInfoResult = trackInfoFeignClient.getTrackInfoById(trackId);
            TrackInfo trackInfo = trackInfoResult.getData();
            Assert.notNull(trackInfo,"[AlbumInfoServiceImpl]调用track微服务的[getTrackInfoById]方法出错");
            albumId = trackInfo.getAlbumId();
        } else {
            //买的是vip,无需修改es中专辑的购买量
        }

        albumStatMapper.updateStatNum(albumId,SystemConstant.ALBUM_STAT_BROWSE,orderSize);


    }


    /**
     * 初始化专辑数据表
     * @param albumId 专辑id
     */
    @Transactional(rollbackFor = Exception.class)
    public void initAlbumStat(Long albumId) {
        ArrayList<String> list = new ArrayList<>();
        list.add(SystemConstant.ALBUM_STAT_PLAY);       //播放量维度
        list.add(SystemConstant.ALBUM_STAT_SUBSCRIBE);  //订阅量维度
        list.add(SystemConstant.ALBUM_STAT_BROWSE);     //浏览量维度
        list.add(SystemConstant.ALBUM_STAT_COMMENT);    //评论量维度

        for (String statType : list) {
            AlbumStat albumStat = new AlbumStat();
            albumStat.setAlbumId(albumId);
            albumStat.setStatType(statType);
            albumStat.setStatNum(0);
            albumStatMapper.insert(albumStat);
        }
    }
}
